from time import *

import requests
from datetime import datetime
import math
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib

matplotlib.use('TkAgg')  # 或者 'Qt5Agg'
plt.ion()  # 开启交互模式
listJZ = []
list_time = []


def go_s(jz, sj):
    plt.figure(figsize=(4, 3))
    plt.plot(jz, marker='o', linestyle='-', linewidth=2, markersize=4)
    labels = [sj[0]] + [''] * (len(jz) - 2) + [sj[-1]]
    plt.xticks(range(len(jz)), labels)
    plt.grid(True, alpha=0.3)
    plt.tight_layout()
    plt.show()
    plt.pause(0.5)  # 短暂暂停以确保图表显示


def get_gz_history(fund_code):
    for i in range(0, 24):  # 爬取12个月的历史净值
        url = f"http://api.fund.eastmoney.com/f10/lsjz?fundCode={fund_code}&pageIndex={i + 1}&pageSize=20"
        headers = {
            'Referer': 'http://fundf10.eastmoney.com',
            'User-Agent': 'Mozilla/5.0'
        }
        r = requests.get(url, headers=headers, timeout=20)
        data = r.json()['Data']['LSJZList']
        for get_ls_num in range(len(data)):
            listJZ.append(float(data[get_ls_num]['DWJZ']))  # 保存所有历史净值
            list_time.append(data[get_ls_num]['FSRQ'])  # 保存最近更新的历史净值的时间


if __name__ == '__main__':
    jj_rc = pd.read_excel(r'../Fund_form_files/JJ_模拟.xlsx', dtype={'基金代码': str, '基金名称': str, '板块': str})
    jj_code = jj_rc['基金代码'].values
    jj_name = jj_rc['基金名称'].values
    jj_type = jj_rc['板块'].values
    for i in range(len(jj_code)):
        print(f'{i + 1}.{jj_name[i]}({jj_type[i]})')
    qu = input('选择你要模拟的基金:')
    code = jj_code[int(qu) - 1]
    print(f'正在模拟交易{jj_name[int(qu) - 1]}({code})')
    get_gz_history(code)
    cash = 10000
    ben_mon = 10000
    inventory = 0
    day = len(listJZ) - 1
    buy_records = []
    num = 0  # 累计操作次数
    ma5_ok = '🚫'
    ma20_ok = '🚫'
    min5_ok = '🚫'
    min20_ok = '🚫'
    up_ok = '🚫'
    low_ok = '🚫'
    ma5_big_ma20 = '🚫'
    upper_band = 0
    lower_band = 0
    cross_signal = '🚫'
    while True:
        yle = cash - ben_mon
        price = listJZ[day]
        # =========================================================================
        if day < len(listJZ) - 1:
            zf = (price - listJZ[day + 1]) / listJZ[day + 1] * 100
        else:
            zf = 0
        # MA5和MA20以及昨日金死叉的判断=================================================
        if day < len(listJZ) - 5:
            ma5 = sum(listJZ[-(len(listJZ) - day - 1):][:5]) / 5
            if price > ma5:
                ma5_ok = '⬆️'
            else:
                ma5_ok = '⬇️'
        else:
            ma5 = 0
        if day < len(listJZ) - 20:
            ma20 = sum(listJZ[-(len(listJZ) - day - 1):][:20]) / 20
            # 走势图
            # go_s(listJZ[-(len(listJZ) - day - 1):][:40][::-1], list_time[-(len(listJZ) - day - 1):][:40][::-1])
            if price > ma20:
                ma20_ok = '⬆️'
            else:
                ma20_ok = '⬇️'
        else:
            ma20 = 0
        # --------------------------------
        if ma5 != 0 and ma20 != 0:
            prev_ma5 = sum(listJZ[-(len(listJZ) - day - 2):][:5]) / 5  # 前前一天的MA5
            prev_ma20 = sum(listJZ[-(len(listJZ) - day - 2):][:20]) / 20  # 前前一天的MA20
            # 金叉死叉判断
            if prev_ma5 != 0 and prev_ma20 != 0:
                # 金叉条件：今日ma5>ma20 且 昨日ma5<=ma20
                if prev_ma5 >= prev_ma20 and ma5 > ma20:
                    cross_signal = "💰金叉"
                    sleep(2)
                # 死叉条件：今日ma5<ma20 且 昨日ma5>=ma20
                elif prev_ma5 >= prev_ma20 and ma5 < ma20:
                    cross_signal = "💀死叉"
                    sleep(2)
                else:
                    cross_signal = "➖无交叉"
            else:
                cross_signal = "📊数据不足"
            # --------------------------------`
            # 计算20日标准差(波动率)和20日上下轨
            my_bz_c = math.sqrt(sum((x - ma20) ** 2 for x in listJZ[-(len(listJZ) - day - 1):][:20]) / 20)
            upper_band = ma20 + 2 * my_bz_c  # 布林带上轨 = 中轨 + 2倍标准差
            lower_band = ma20 - 2 * my_bz_c  # 布林带下轨 = 中轨 - 2倍标准差
            # 一些常规提示判断
            if price >= upper_band:
                up_ok = '✔️'
                low_ok = '❌'
            elif price <= lower_band:
                low_ok = '✔️'
                up_ok = '❌'
            else:
                up_ok = '❌'
                low_ok = '❌'
            if ma5 > ma20:
                ma5_big_ma20 = '✔️'
            else:
                ma5_big_ma20 = '❌'
            min5 = min(listJZ[-(len(listJZ) - day - 1):][:5])
            min20 = min(listJZ[-(len(listJZ) - day - 1):][:20])
            if price < min5 and price < min20:
                min5_ok = '✔️'
                min20_ok = '✔️'
            elif price < min5:
                min5_ok = '✔️'
                min20_ok = '❌'
            elif price < min20:
                min5_ok = '❌'
                min20_ok = '✔️'
            else:
                min5_ok = '❌'
                min20_ok = '❌'
        # ============================================================
        begin_day = datetime.strptime(list_time[len(listJZ) - 1], "%Y-%m-%d")
        now_day = datetime.strptime(list_time[day], "%Y-%m-%d")
        tz_days = now_day - begin_day
        print(f'🧐今天是{list_time[day]}号==第{tz_days.days}天===')
        print(f"🛒净值: ${price} | 涨幅：{zf:.2f}%")
        print(f"💹MA5: ${ma5:.4f}{ma5_ok} | MA20：${ma20:.4f}{ma20_ok}|MA5>MA20❔{ma5_big_ma20}{cross_signal}")
        print(f"💹Up: ${upper_band:.4f}{up_ok}| Low：${lower_band:.4f}{low_ok}")
        print(f'💹MIN5❔{min5_ok}|MIN20❔{min20_ok}')
        print(f"💰现金: ${cash:.2f}")
        print(f"📈盈利: ${yle:.2f}")
        print(f"📦库存: {inventory:.3f}")
        if len(buy_records) != 0:
            max_jz = buy_records[0]['price']
            min_jz = buy_records[len(buy_records) - 1]['price']
            # 计算总投入金额和总股数
            total_amount = sum(record['amount'] for record in buy_records)
            total_quantity = sum(record['quantity'] for record in buy_records)
            average_cost = total_amount / total_quantity if total_quantity > 0 else 0
            cb_cy = (price - average_cost) / average_cost * 100
            if cb_cy >= 8:
                xh = '✅'
            else:
                xh = '❎'
            print(f"成本：{average_cost:.3f}|总盈亏：{cb_cy:.2f}% 达到目标收益？{xh}")
            print(f"最高价：{max_jz}|最高价涨幅：{(price - max_jz) / max_jz * 100:.2f}%")
            print(f"最低价：{min_jz}|最低价涨幅：{(price - min_jz) / min_jz * 100:.2f}%")
        action = input("操作(1买/2卖/3清仓结算): ").lower()
        if action == '1':
            num = num + 1
            amount = float(input("购买金额: $"))
            if amount <= cash:
                quantity = amount / price
                inventory += quantity
                cash -= amount
                buy_records.append({
                    'amount': amount,
                    'price': price,
                    'quantity': quantity,
                    'time': list_time[day]
                })
                print(f"购买了 {quantity:.2f} 单位")
            else:
                print("现金不足")
        elif action == '2':
            num = num + 1
            quantity = float(input("出售数量: "))
            if quantity <= inventory:
                print(f'当前库存={inventory}')
                revenue = quantity * price * (1 - 0.005)
                inventory -= quantity
                cash += revenue
                if len(buy_records) != 0:
                    del buy_records[len(buy_records) - 1]  # 每次卖出自动删除最后一个买入记录
                print(f"出售收入: ${revenue:.2f}")
            else:
                print("库存不足重新今日操作")
                day = day + 1
        elif action == '3':
            num = num + 1
            cash += inventory * price * (1 - 0.005)
            print(f'本金${ben_mon},剩余本金${cash},清仓净值{price},清空库存结余{inventory * price * (1 - 0.005):.2f}$')
            end_yl = cash - ben_mon
            print(f'投资{tz_days.days}天以来收益${end_yl:.2f},期间买卖{num}次')
            if len(buy_records) != 0:
                buy_records.clear()
                inventory = 0
        plt.close()
        print("\n买入记录:")
        for record in buy_records:
            date1 = datetime.strptime(record['time'], "%Y-%m-%d")
            date2 = datetime.strptime(list_time[day], "%Y-%m-%d")
            day_c = (date2 - date1).days
            print(
                f"      时间差：{day_c}天,金额:${record['amount']:.2f}, "
                f"单价:{record['price']}, 份额:{record['quantity']:.3f}")
        day = day - 1
